#include "widget.h"
#include "GL/gl.h"
#include <QImage>
#include <math.h>
#include <QTime>

QVector3D cameraPos   = QVector3D(0.0f, 1.0f,  -5.0f); //摄像机初始化在z轴负方向
QVector3D cameraFront = QVector3D(6.12303e-17f, 0.0f, 1.0f);
QVector3D cameraUp    = QVector3D(0.0f, 1.0f,  0.0f);

int deltaTime = 0; // 当前帧与上一帧的时间差
QTime lastTime;

float lastX = 0, lastY = 0;
float pitch = 0, yaw = 90, roll = 0; //初始化摄像机方向 俯仰角(Pitch)、偏航角(Yaw)和滚转角(Roll)
float fov = 45.0;

Widget::Widget(QOpenGLWidget *parent)
    :QOpenGLWidget(parent)
{
    setWindowTitle("光照贴图");
    m_angle = 0.0;
    m_timer = new QTimer;
    m_timer->setInterval(30);
    connect(m_timer, SIGNAL(timeout()), this, SLOT(timeout()));
    m_timer->start();

    lastTime.start();
    setMouseTracking(true);
    firstMouse = 0;
    setWindowState(Qt::WindowMaximized);

    lastX = width()/2;
    lastY = height()/2;

    m_cursor = cursor();
    lightShader = new LightShader(this);
    cubeShader = new CubeShader(this);
}

Widget::~Widget()
{
}

void Widget::initializeGL()
{
    initializeOpenGLFunctions();

    glEnable(GL_TEXTURE_2D);
    glEnable(GL_DEPTH_TEST);

    //VAO，VBO数据部分
    float vertices[] = {
        // positions          // normals           // texture coords
        -0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  0.0f, 0.0f,
         0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  1.0f, 0.0f,
         0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  1.0f, 1.0f,
         0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  1.0f, 1.0f,
        -0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  0.0f, 1.0f,
        -0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  0.0f, 0.0f,

        -0.5f, -0.5f,  0.5f,  0.0f,  0.0f, 1.0f,   0.0f, 0.0f,
         0.5f, -0.5f,  0.5f,  0.0f,  0.0f, 1.0f,   1.0f, 0.0f,
         0.5f,  0.5f,  0.5f,  0.0f,  0.0f, 1.0f,   1.0f, 1.0f,
         0.5f,  0.5f,  0.5f,  0.0f,  0.0f, 1.0f,   1.0f, 1.0f,
        -0.5f,  0.5f,  0.5f,  0.0f,  0.0f, 1.0f,   0.0f, 1.0f,
        -0.5f, -0.5f,  0.5f,  0.0f,  0.0f, 1.0f,   0.0f, 0.0f,

        -0.5f,  0.5f,  0.5f, -1.0f,  0.0f,  0.0f,  1.0f, 0.0f,
        -0.5f,  0.5f, -0.5f, -1.0f,  0.0f,  0.0f,  1.0f, 1.0f,
        -0.5f, -0.5f, -0.5f, -1.0f,  0.0f,  0.0f,  0.0f, 1.0f,
        -0.5f, -0.5f, -0.5f, -1.0f,  0.0f,  0.0f,  0.0f, 1.0f,
        -0.5f, -0.5f,  0.5f, -1.0f,  0.0f,  0.0f,  0.0f, 0.0f,
        -0.5f,  0.5f,  0.5f, -1.0f,  0.0f,  0.0f,  1.0f, 0.0f,

         0.5f,  0.5f,  0.5f,  1.0f,  0.0f,  0.0f,  1.0f, 0.0f,
         0.5f,  0.5f, -0.5f,  1.0f,  0.0f,  0.0f,  1.0f, 1.0f,
         0.5f, -0.5f, -0.5f,  1.0f,  0.0f,  0.0f,  0.0f, 1.0f,
         0.5f, -0.5f, -0.5f,  1.0f,  0.0f,  0.0f,  0.0f, 1.0f,
         0.5f, -0.5f,  0.5f,  1.0f,  0.0f,  0.0f,  0.0f, 0.0f,
         0.5f,  0.5f,  0.5f,  1.0f,  0.0f,  0.0f,  1.0f, 0.0f,

        -0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,  0.0f, 1.0f,
         0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,  1.0f, 1.0f,
         0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,  1.0f, 0.0f,
         0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,  1.0f, 0.0f,
        -0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,  0.0f, 0.0f,
        -0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,  0.0f, 1.0f,

        -0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,  0.0f, 1.0f,
         0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,  1.0f, 1.0f,
         0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,  1.0f, 0.0f,
         0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,  1.0f, 0.0f,
        -0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,  0.0f, 0.0f,
        -0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,  0.0f, 1.0f
    };

    memcpy((char*)lightShader->vertices, (char*)vertices, sizeof(vertices));
    lightShader->initializeGL();

    memcpy((char*)cubeShader->vertices, (char*)vertices, sizeof(vertices));
    cubeShader->initializeGL();
    cubeShader->lightColor = QVector3D(1.0f, 1.0f, 1.0f);

    cubeShader->viewPos = cameraPos;
}

void Widget::resizeGL(int w, int h)
{
    glViewport(0, 0, w, h);
}

void Widget::paintGL()
{
    deltaTime = lastTime.elapsed();
    lastTime.restart();

    glClearColor(0.2f, 0.3f, 0.3f, 0.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    QMatrix4x4 projection, view;

    float ratio = (float)width() / (float)height();
    projection.perspective(fov, ratio, 0.1f, 100.0f);
    view.lookAt(cameraPos, cameraPos+cameraFront, cameraUp);

    lightShader->projection = projection;
    lightShader->view = view;
    lightShader->paintGL();

    QMatrix4x4 model;
    model.translate(QVector3D(0.0f,  0.0f,  0.0f));
    model.rotate(0.0f, QVector3D(0.5f, 1.0f, 0.0f));

    cubeShader->projection = projection;
    cubeShader->view = view;
    cubeShader->model = model;
    cubeShader->paintGL();

}

void Widget::keyPressEvent(QKeyEvent *event)
{
    float cameraSpeed = 0.01f * deltaTime;
    if(event->key() == Qt::Key_A)
    {
        cameraPos -= QVector3D::crossProduct(cameraFront, cameraUp).normalized() * cameraSpeed;
    }
    else if(event->key() == Qt::Key_D)
    {
        cameraPos += QVector3D::crossProduct(cameraFront, cameraUp).normalized() * cameraSpeed;
    }
    else if(event->key() == Qt::Key_W)
    {
        cameraPos += cameraSpeed * cameraFront;
    }
    else if(event->key() == Qt::Key_S)
    {
        cameraPos -= cameraSpeed * cameraFront;
    }
    cubeShader->viewPos = cameraPos;
    QOpenGLWidget::keyPressEvent(event);
}

void Widget::mousePressEvent(QMouseEvent *event)
{
    QOpenGLWidget::mousePressEvent(event);
}

void Widget::mouseMoveEvent(QMouseEvent *event)
{
    //    qInfo()<<event->pos();
    int xpos = event->pos().x();
    int ypos = event->pos().y();

    if(firstMouse<2)
    {
        firstMouse++;

        lastX = xpos;
        lastY = ypos;

        m_cursor.setPos(width()/2, height()/2); //初始化鼠标为中心位置
        if(firstMouse==1) return;
    }

    float xoffset = xpos - lastX;
    float yoffset = lastY - ypos; // 注意这里是相反的，因为y坐标是从底部往顶部依次增大的
    lastX = xpos;
    lastY = ypos;

    float sensitivity = 0.1f; // 灵敏度
    xoffset *= sensitivity;
    yoffset *= sensitivity;

    yaw   += xoffset;
    pitch += yoffset;

    if(pitch > 89.0f)
        pitch =  89.0f;
    if(pitch < -89.0f)
        pitch = -89.0f;

    QVector3D front;
    front.setX(cos(pitch/180.0*M_PI) * cos(yaw/180.0*M_PI));
    front.setY(sin(pitch/180.0*M_PI));
    front.setZ(cos(pitch/180.0*M_PI) * sin(yaw/180.0*M_PI));
    cameraFront = front.normalized();

    //    qInfo()<<event->pos() << xoffset << yoffset
    //          << "===" << cameraFront
    //          << pitch << yaw
    //    <<"XXX" << cameraPos+cameraFront;

    QOpenGLWidget::mousePressEvent(event);
}

void Widget::wheelEvent(QWheelEvent *event)
{
    //    qInfo()<<event->angleDelta();
    if(event->angleDelta().y() > 0)
    {
        // scroll up 120
    }
    else if(event->angleDelta().y() < 0)
    {
        // scroll down -120
    }

    if(fov >= 1.0f && fov <= 45.0f)
        fov -= event->angleDelta().y() / 120.0;

    if(fov <= 1.0f)
        fov = 1.0f;
    if(fov >= 45.0f)
        fov = 45.0f;

    QOpenGLWidget::wheelEvent(event);
}

void Widget::timeout()
{
    m_angle+=1.0;
    if(m_angle>360.0) m_angle = 0.0;
//    cubeShader->lightColor = QVector3D(sin(m_angle * 2.0f), sin(m_angle * 0.7f), sin(m_angle * 1.3f));
    QMatrix4x4 lightPos;

    cubeShader->pos = QVector3D( sin(m_angle/180.0*M_PI) * 10.0, 0.5f, cos(m_angle/180.0*M_PI) * 10.0);

    lightPos.scale(QVector3D(0.2f, 0.2f, 0.2f));
    lightPos.translate(cubeShader->pos);

    lightShader->pos = lightPos;

    update();
}
